 /*****************************************************************************
*
* 文件摘要:
   驱动一个led，使用字符设备动态插入内核                                             
-------------------------------------------------------------------------------
*
* 文件名称:    led_blink.c
* 软件设计: Eliot_shao 爱霞霞啦
* 编译环境:	arm-linux-gcc(version 3.4.1)
* 运行环境: arm-linux
* MCU类型: AT91SAM9260
* 版本控制: VERSION 1.0
* 创建日期: 2015.02.27
* 修改人 :   
* 修改时间:                        
* 修改内容:  
*****************************************************************************/

#include <linux/module.h>
#include <linux/mm.h>
#include <linux/io.h>
#include <linux/kernel.h> 			/* printk()在这个文件里 */
#include <asm/uaccess.h> 			/* copy_to_user(), copy_from_user */
#include <linux/fs.h> 				/* struct file_operations, register_chrdev(), ... */
#include <linux/sched.h>			/* 和任务调度有关 */
#include <linux/types.h> 			/* u8, u16, u32 ... */
#include <linux/version.h>
#include <linux/init.h>       //module_init() and module_exit() 定义在该文件中 
#include <linux/slab.h>
#include <asm/page.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/cdev.h>
#include "IOdrv.h"


struct led_blink_dev {
		struct cdev cdev ;
		int led_blink ;
};
struct led_blink_dev *led_blinkdev;


static ssize_t led_blink_open(struct inode *inode,struct file *file)
{
	struct led_blink_dev *dev;
	printk("<0>" "I am hero ! \n");
    //根据inode结构的cdev字段，获得整个设备结构的指针

    dev=container_of(inode->i_cdev, struct led_blink_dev, cdev);

    //将file结构中的private_data字段指向已分配的设备结构

    file->private_data=dev;

    return 0;
}
static ssize_t led_blink_read(struct file *filp,char *buf,size_t count,loff_t *f_pos)
{
	return 0 ;
}
static ssize_t led_blink_write(struct file *filp,const char *buf,size_t count,loff_t *ppos)
{
	return 0 ;
}
static ssize_t led_blink_release(struct inode *inode,struct file *file)
{
	printk("<0>" "I am hero 2! \n");
	return 0 ;
}
void __iomem *pioA_base;

#define  LEDBlink_H      _IO('k',0x01)  
#define  LEDBlink_L      _IO('k',0x02)  
static ssize_t led_blink_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	AT91S_PIO  *AT91_PIO;
	switch(cmd)
	{
		case LEDBlink_H:
			AT91_PIO = (AT91PS_PIO)pioA_base;
			AT91_PIO->PIO_PER =  AT91C_PIO_PA8 ;//使能PA8
			AT91_PIO->PIO_OER =  AT91C_PIO_PA8 ;//输出使能
			AT91_PIO->PIO_SODR = AT91C_PIO_PA8 ; //置位pa8
			break ;
		case LEDBlink_L:
			AT91_PIO = (AT91PS_PIO)pioA_base;
			AT91_PIO->PIO_PER =  AT91C_PIO_PA8 ;//使能PA8
			AT91_PIO->PIO_OER =  AT91C_PIO_PA8 ;//输出使能
			AT91_PIO->PIO_CODR = AT91C_PIO_PA8 ; //清除PA8
			break ;
			default: break ;
	}
	return 0 ;
}


static struct file_operations ledblink_ops = {
					                      		.owner = THIS_MODULE,
					                      		.open  = led_blink_open,
					                     		.read  = led_blink_read,
					                     		.write = led_blink_write,
					                     		.ioctl = led_blink_ioctl,
					                     		.release = led_blink_release,
	                           			 };


int dev_major = 250;
int dev_minor = 1;



static int __init led_blink_init()
{
	int ret ,err;
	printk("<2>" "Init led blink ,hardware led is DS5(PA8)\n");
	
	dev_t devno=MKDEV(dev_major, dev_minor);
	//ret = alloc_chrdev_region(&devno, dev_minor, 1, "Ledblink");
	//dev_major=MAJOR(devno);//申请设备号
	ret=register_chrdev_region(devno, 1, "Ledblink");
	pioA_base = ioremap(0xFFFFF400,512);//IO端口映射到io内存

	led_blinkdev=kmalloc(sizeof(struct led_blink_dev), GFP_KERNEL);//申请一个led设备，包含cdev
	if(!led_blinkdev)
	{
		ret = -ENOMEM ;
		printk("<1>" "fail to kmalloc mem! \n");
		return ret ;
	}
	
	led_blinkdev->led_blink = 0 ;
	cdev_init(&led_blinkdev->cdev, &ledblink_ops); //初始化led_blinkdev
	led_blinkdev->cdev.owner = THIS_MODULE ;
	err=cdev_add(&led_blinkdev->cdev, devno, 1);//向内核添加cdev

	if(err<0)
		printk("<6>" "cdev_add erro!\n");
	else
		printk("<6>" "cdev_add OK!\n");
	return ret ;
	
}
static void __exit led_blink_exit()
{

	//释放IO内存
	//释放led_blinkdev
	//删除cdev

	dev_t devno=MKDEV(dev_major, dev_minor);
	cdev_del(&led_blinkdev->cdev);
	
	iounmap(pioA_base);

	kfree(led_blinkdev);

	unregister_chrdev_region(devno, 1);

	printk("<1>" "led_blinkdev unregister success\n");
}


module_init(led_blink_init);

module_exit(led_blink_exit);

MODULE_LICENSE("GPL");


